// --------------------- 包导入（功能模块依赖） ---------------------
import javax.swing.*;          // 导入Swing库，用于创建图形用户界面组件（如JFrame窗口、JButton按钮、JTextField文本框）
import java.awt.*;           // 导入AWT库，用于图形绘制、布局管理（BorderLayout、GridLayout）和颜色设置
import java.awt.event.*;     // 导入事件处理库，用于处理按钮点击（ActionListener）和键盘输入（KeyAdapter）
import java.io.File;         // 导入文件操作类，用于加载背景音乐文件（拓展功能依赖）
import java.time.LocalDate;  // 导入本地日期类，用于获取当前日期（拓展功能）
import java.time.LocalTime;  // 导入本地时间类，用于获取当前时间（拓展功能）
import java.util.ArrayList; // 导入ArrayList集合，用于动态存储历史记录（基础功能数据结构）
import java.util.List;       // 导入List接口，定义历史记录类型（基础功能）
import javax.script.*;       // 导入脚本引擎，解析数学表达式（核心计算依赖）
import javax.sound.sampled.*;// 导入音频库，实现背景音乐（拓展功能核心）

/**
 * 高级科学计算器类
 * 功能：实现基本四则运算、科学计算、日期时间显示、历史记录、自动播放背景音乐
 * 优化点：界面布局、输入控制、结果格式化、异常处理
 * 拓展功能：科学计算、历史记录、日期时间、背景音乐、键盘快捷键
 */
public class Calculator extends JFrame implements ActionListener {
    // --------------------- 界面组件声明 ---------------------
    private JPanel north, center, east;        // 三面板布局：north顶部（文本框）、center中部（按钮）、east右侧（历史记录）
    private JTextField field;                // 计算显示文本框，不可编辑
    private JButton[] btns;                   // 按钮数组，存储26个功能按钮
    
    // --------------------- 计算状态变量 ---------------------
    private double lastResult = 0;            // 保存上一次计算结果，用于连续计算
    private List<String> history = new ArrayList<>(); // 历史记录列表，存储计算表达式和结果
    
    // --------------------- 历史记录组件 ---------------------
    private JTextArea historyArea;            // 历史记录文本区域
    private JScrollPane historyScrollPane;    // 为历史记录添加滚动条（优化：支持长历史查看）
    
    // --------------------- 背景音乐组件 ---------------------
    private Clip backgroundMusic;             // 音频剪辑对象，播放背景音乐（拓展功能核心）

    // --------------------- 构造函数（窗口初始化） ---------------------
    public Calculator() {
        // 窗口基础设置
        setTitle("高级科学计算器");             // 设置窗口标题
        setSize(1000, 700);                   // 窗口大小（宽1000，高700），适配历史面板（优化：宽屏布局）
        setDefaultCloseOperation(EXIT_ON_CLOSE);// 关闭窗口时退出程序
        setLocationRelativeTo(null);           // 窗口居中显示
        
        // 功能初始化
        initComponent();                       // 初始化界面组件（基础功能）
        initBackgroundMusic();                 // 初始化背景音乐（拓展功能）
        setVisible(true);                      // 显示窗口
        
        // 键盘事件监听（拓展功能：支持键盘快捷键）
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                handleKeyPress(e.getKeyChar()); // 处理键盘输入
            }
        });
        setFocusable(true);                    // 设置窗口可获得焦点
        requestFocusInWindow();                // 请求焦点，使键盘事件生效
    }

    // --------------------- 界面组件初始化 ---------------------
    private void initComponent() {
        // 背景与布局
        getContentPane().setBackground(new Color(240, 240, 240)); // 浅灰色背景（优化：视觉舒适度）
        setLayout(new BorderLayout(5, 0));                        // 边框布局，水平间距5px
        
        // 计算器主面板（左侧区域）
        JPanel calculatorPanel = new JPanel(new BorderLayout());   // 左侧计算器面板
        
        north = new JPanel();                                     // 顶部面板（放文本框）
        center = new JPanel();                                    // 中部面板（放按钮）
        
        // 显示文本框设置（优化：尺寸和样式）
        field = new JTextField();
        field.setPreferredSize(new Dimension(650, 100)); // 文本框大小650×100（优化：适配长表达式）
        field.setEditable(false);                         // 禁止手动编辑（优化：安全性）
        field.setFont(new Font("Microsoft YaHei", Font.BOLD, 35)); // 大字体中文字体（优化：可读性）
        field.setHorizontalAlignment(JTextField.RIGHT);  // 文本右对齐（符合计算器习惯）
        field.setBackground(new Color(255, 255, 255));    // 白色背景
        field.setForeground(new Color(51, 51, 51));       // 深灰色文本（优化：对比度）
        field.setBorder(BorderFactory.createLineBorder(new Color(200, 200, 200), 2)); // 浅灰边框
        
        // 按钮定义与初始化
        String[] str = new String[] {                        // 26个按钮文本
            "7", "8", "9", "+", "sin",
            "4", "5", "6", "-", "cos",
            "1", "2", "3", "×", "tan",
            "0", ".", "=", "÷", "ln",
            "C", "B", "T", "S", "log",
            "H", "W.", "R.", "H.", "H"
        };
        btns = new JButton[str.length];
        for (int i = 0; i < btns.length; i++) {
            btns[i] = new JButton(str[i]);
            
            // 按钮颜色分类（优化：按功能区分颜色）
            if (i >= 21) { btns[i].setBackground(new Color(100, 200, 100)); } // 历史按钮（绿色）
            else if (i >= 16) { btns[i].setBackground(new Color(230, 100, 100)); } // 功能按钮（红色）
            else if (i % 5 == 4) { btns[i].setBackground(new Color(180, 100, 230)); } // 科学按钮（紫色）
            else if (i % 5 == 3) { btns[i].setBackground(new Color(100, 150, 230)); } // 运算符（蓝色）
            else { btns[i].setBackground(new Color(250, 250, 250)); } // 数字按钮（浅灰）
            
            // 按钮样式统一
            btns[i].setForeground(i >= 16 ? Color.WHITE : new Color(51, 51, 51)); // 非数字按钮白字
            btns[i].setBorder(BorderFactory.createLineBorder(new Color(200, 200, 200), 1)); // 细边框
            btns[i].setFocusPainted(false); // 取消焦点框（优化：视觉简洁）
            btns[i].setFont(new Font("Microsoft YaHei", Font.BOLD, 25)); // 统一字体
        }
        
        // 面板布局
        north.setLayout(new BorderLayout());              // 顶部面板用边框布局
        center.setLayout(new GridLayout(6, 5, 5, 5));     // 中部用6×5网格布局，间距5px（优化：紧凑排列）
        north.add(field, BorderLayout.CENTER);            // 文本框放顶部中央
        for (JButton btn : btns) center.add(btn);         // 按钮添加到中部
        
        calculatorPanel.add(north, BorderLayout.NORTH);   // 顶部面板添加到计算器主面板顶部
        calculatorPanel.add(center, BorderLayout.CENTER); // 中部面板添加到计算器主面板中部
        
        // 历史记录面板（右侧区域）
        east = new JPanel(new BorderLayout());            // 右侧历史面板
        east.setPreferredSize(new Dimension(300, 700));   // 历史面板宽300px
        
        JLabel historyLabel = new JLabel("计算历史");      // 历史标题
        historyLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 20));
        historyLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));
        east.add(historyLabel, BorderLayout.NORTH);       // 标题放顶部
        
        // 历史记录显示
        historyArea = new JTextArea();                    // 历史文本区域
        historyArea.setEditable(false);                   // 不可编辑
        historyArea.setFont(new Font("Microsoft YaHei", Font.PLAIN, 16));
        historyArea.setLineWrap(true); historyArea.setWrapStyleWord(true); // 自动换行
        historyScrollPane = new JScrollPane(historyArea); // 添加滚动条（优化：长历史查看）
        east.add(historyScrollPane, BorderLayout.CENTER); // 滚动条放中央
        
        // 清空历史按钮
        JButton clearHistoryBtn = new JButton("清空历史");
        clearHistoryBtn.addActionListener(e -> clearHistory()); // 点击清空历史
        east.add(clearHistoryBtn, BorderLayout.SOUTH);        // 按钮放底部
        
        // 面板添加到窗口
        add(calculatorPanel, BorderLayout.WEST);             // 计算器放左侧
        add(east, BorderLayout.EAST);                       // 历史放右侧
        for (JButton btn : btns) btn.addActionListener(this); // 注册按钮事件
    }

    // --------------------- 背景音乐功能（拓展功能） ---------------------
    private void initBackgroundMusic() {
        try {
            // 音频文件路径（需手动修改为存在的文件）
            File audioFile = new File("C:\\Users\\lenovo\\Desktop\\23jianxi\\_- 富士山下_L.wav");
            
            // 异常处理：文件不存在
            if (!audioFile.exists()) {
                System.out.println("背景音乐文件不存在: " + audioFile.getAbsolutePath());
                return;
            }
            
            // 音频流加载
            AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
            AudioFormat format = audioStream.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, format);
            
            // 异常处理：格式不支持
            if (!AudioSystem.isLineSupported(info)) {
                System.out.println("不支持的音频格式");
                return;
            }
            
            // 初始化音频剪辑并循环播放
            backgroundMusic = (Clip) AudioSystem.getLine(info);
            backgroundMusic.open(audioStream);
            backgroundMusic.loop(Clip.LOOP_CONTINUOUSLY); // 无限循环
        } catch (Exception e) {
            System.out.println("背景音乐错误: " + e.getMessage());
        }
    }

    // --------------------- 按钮点击处理 ---------------------
    private void setBtnText(String text) {
        String currentText = field.getText();
        
        // 历史按钮处理
        if (text.equals("H")) { 
            toggleHistoryPanel(); // 切换历史面板显示状态
            return;
        }
        
        // 运算符输入控制（优化：防止无效输入）
        if (isOperator(text)) {
            if (currentText.isEmpty()) return; // 空输入不能输入运算符
            if (isOperator(currentText.charAt(currentText.length() - 1))) return; // 防止连续运算符
        } 
        
        // 小数点输入控制（优化：自动补零）
        else if (text.equals(".")) {
            if (currentText.isEmpty()) {
                field.setText("0."); // 空输入自动补0
                return;
            }
            char lastChar = currentText.charAt(currentText.length() - 1);
            if (isOperator(lastChar)) {
                field.setText(currentText + "0."); // 运算符后自动补0
                return;
            }
            // 防止重复小数点
            String[] parts = currentText.split("(?<=[+\\-×÷])|(?=[+\\-×÷])");
            if (parts[parts.length - 1].contains(".")) return;
        }
        
        // 科学计算处理（拓展功能）
        if (isScientificFunction(text)) {
            try {
                double value = Double.parseDouble(currentText);
                double result = calculateScientificFunction(text, value);
                addToHistory(currentText, text, formatResult(result));
                field.setText(formatResult(result));
            } catch (NumberFormatException e) {
                field.setText("错误: 请先输入数字");
            }
            return;
        }
        
        // 功能按钮处理
        switch (text) {
            case "C": field.setText(""); break;                  // 清空
            case "B": if (!currentText.isEmpty()) field.setText(currentText.substring(0, currentText.length() - 1)); break; // 退格
            case "T": field.setText(LocalTime.now().toString()); break; // 显示时间（拓展功能）
            case "S": field.setText(LocalDate.now().toString()); break; // 显示日期（拓展功能）
            case "=": // 计算结果
                try {
                    // 修复负数处理：-5→0-5
                    String expression = currentText
                        .replace("×", "*").replace("÷", "/")
                        .replaceAll("(?<!\\d|\\.|\\))\\-", "0-");
                    
                    ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
                    double result = Double.parseDouble(engine.eval(expression).toString());
                    addToHistory(currentText, "=", formatResult(result));
                    field.setText(formatResult(result));
                } catch (Exception e) { field.setText("计算错误"); }
                break;
            default: field.setText(currentText + text); break;    // 数字输入
        }
    }
    
    // --------------------- 历史记录管理 ---------------------
    private void addToHistory(String expression, String operator, String result) {
        String record = expression + " " + operator + " " + result;
        history.add(record);
        updateHistoryDisplay();
    }
    
    private void updateHistoryDisplay() {
        StringBuilder historyText = new StringBuilder();
        // 倒序遍历，最新记录在前（优化：用户体验）
        for (int i = history.size() - 1; i >= 0; i--) {
            historyText.append(history.get(i)).append("\n\n");
        }
        historyArea.setText(historyText.toString());
        // 自动滚动到最新记录（优化：用户体验）
        SwingUtilities.invokeLater(() -> historyArea.setCaretPosition(0));
    }
    
    private void clearHistory() {
        history.clear();
        historyArea.setText("");
    }
    
    private void toggleHistoryPanel() {
        if (east.isVisible()) {
            east.setVisible(false);
            setSize(700, 700); // 隐藏时缩小窗口（优化：布局自适应）
        } else {
            east.setVisible(true);
            setSize(1000, 700); // 显示时恢复窗口
        }
    }
    
    // --------------------- 辅助方法 ---------------------
    private String formatResult(double result) {
        // 整数去尾零（优化：结果显示）
        return result == (int) result ? String.valueOf((int) result) : String.valueOf(result);
    }
    
    private boolean isOperator(String text) {
        return text.equals("+") || text.equals("-") || text.equals("×") || text.equals("÷");
    }
    
    private boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '×' || c == '÷';
    }
    
    private boolean isScientificFunction(String text) {
        return text.equals("sin") || text.equals("cos") || text.equals("tan") || 
               text.equals("ln") || text.equals("log");
    }
    
    private double calculateScientificFunction(String func, double value) {
        switch (func) {
            case "sin": return Math.sin(Math.toRadians(value)); // 角度转弧度
            case "cos": return Math.cos(Math.toRadians(value));
            case "tan": return Math.tan(Math.toRadians(value));
            case "ln": return Math.log(value);
            case "log": return Math.log10(value);
            default: return value;
        }
    }
    
    private void handleKeyPress(char keyChar) {
        String keyText = Character.toString(keyChar);
        
        if (keyChar >= '0' && keyChar <= '9') {
            setBtnText(keyText); // 数字键输入
        } 
        else if (keyChar == '+' || keyChar == '-' || keyChar == '*' || keyChar == '/') {
            setBtnText(keyText.replace('*', '×').replace('/', '÷')); // 运算符键输入
        } 
        else if (keyChar == '.') {
            setBtnText("."); // 小数点
        } 
        else if (keyChar == '\n') {
            setBtnText("="); // 回车键=
        } 
        else if (keyChar == '\b') {
            setBtnText("B"); // 退格键B
        } 
        else if (keyChar == 27) {
            setBtnText("C"); // ESC键C
        }
    }

    // --------------------- 事件处理 ---------------------
    @Override
    public void actionPerformed(ActionEvent a) {
        if (a.getSource() instanceof JButton) {
            JButton btn = (JButton) a.getSource();
            String text = btn.getText();
            setBtnText(text);
        }
    }

    // --------------------- 主方法 ---------------------
    public static void main(String[] args) {
        SwingUtilities.invokeLater(Calculator::new); // 线程安全的UI创建
    }
}